package linked;

/**
 * 24. 两两交换链表中的节点
 * 给你一个链表，两两交换其中相邻的节点，并返回交换后链表的头节点。
 * 你必须在不修改节点内部的值的情况下完成本题（即，只能进行节点交换）。
 * <p>
 * 示例 1：
 * 输入：head = [1,2,3,4]
 * 输出：[2,1,4,3]
 * <p>
 * 示例 2：
 * 输入：head = []
 * 输出：[]
 * <p>
 * 示例 3：
 * 输入：head = [1]
 * 输出：[1]
 */
public class Problem_24 {

    /**
     * 方法一：递归
     * 递归的终止条件是链表中没有节点，或者链表中只有一个节点，此时无法进行交换。
     * 如果链表中至少有两个节点，则在两两交换链表中的节点之后，
     * 原始链表的头节点变成新的链表的第二个节点，原始链表的第二个节点变成新的链表的头节点。
     * 链表中的其余节点的两两交换可以递归地实现。
     * 在对链表中的其余节点递归地两两交换之后，更新节点之间的指针关系，即可完成整个链表的两两交换。
     * <p>
     * 具体做法:
     * 用 head 表示原始链表的头节点(新链表的第二个节点)，用 newHead 表示新的链表的头节点(原始链表的第二个节点)，
     * 则原始链表中的其余头节点是 newHead.next。
     * 令 head.next = swapPairs(newHead.next)，表示将其余节点进行两两交换，交换后的新的头节点为 head 的下一个节点。
     * 然后令 newHead.next = head，即完成了所有节点的交换。
     * 最后返回新的链表的头节点 newHead。
     */
    public ListNode swapPairs(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode newHead = head.next;
        head.next = swapPairs(newHead.next);
        newHead.next = head;
        return newHead;
    }

    /**
     * 方法二：迭代
     */
    public ListNode swapPairs_2(ListNode head) {
        ListNode dummyHead = new ListNode(-1, head); //虚拟头结点
        ListNode tempNode = dummyHead;

        while (tempNode.next != null && tempNode.next.next != null) {
            ListNode node1 = tempNode.next;
            ListNode node2 = tempNode.next.next;
            tempNode.next = node2;
            node1.next = node2.next;
            node2.next = node1;
            tempNode = node1;
        }

        return dummyHead.next;
    }

    public class ListNode {
        int val;
        ListNode next;

        ListNode() {
        }

        ListNode(int val) {
            this.val = val;
        }

        ListNode(int val, ListNode next) {
            this.val = val;
            this.next = next;
        }
    }

}
